package es.usc.citius.servando.calendula.settings.database;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Pair;

import org.jetbrains.annotations.NotNull;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import es.usc.citius.servando.calendula.R;
import es.usc.citius.servando.calendula.drugdb.DBRegistry;
import es.usc.citius.servando.calendula.jobs.CheckDatabaseUpdatesJob;
import es.usc.citius.servando.calendula.mvp.BasePresenter;
import es.usc.citius.servando.calendula.settings.CalendulaSettingsActivity;
import es.usc.citius.servando.calendula.util.LogUtil;
import es.usc.citius.servando.calendula.util.PreferenceKeys;
import es.usc.citius.servando.calendula.util.PreferenceUtils;

public class DatabasePrefsPresenter
        extends BasePresenter<DatabasePrefsContract.View>
        implements DatabasePrefsContract.Presenter{

    private final String TAG = "DatabasePrefsPresenter";

    private String currentDbId;
    private String noneId;
    private String settingUpId;
    private String noneDisplay;
    private String selectIdTemp = null;

    @Override
    public void attachView(@NotNull DatabasePrefsContract.View view) {
        super.attachView(view);
        noneDisplay = view.resolveString(R.string.database_none_display);
        noneId = view.resolveString(R.string.database_none_id);
        settingUpId = view.resolveString(R.string.database_setting_up_id);
    }

    public DatabasePrefsPresenter(String currentDbId){
        this.currentDbId = currentDbId;
    }

    @Override
    public void currentDbUpdated(String dbId) {
        LogUtil.d(TAG, "currentDbUpdated() called with dbId=$dbId");
        currentDbId = dbId;
        view.showSelectedDb(currentDbId);
    }

    @Override
    public boolean selectNewDb(String dbId) {
        LogUtil.d(TAG, "selectNewDb() called with dbId=$dbId");
        if (!dbId.equals(currentDbId)) {
            // if there is no actual update just return true and skip checks
            if (!dbId.equals(noneId) && !dbId.equals(settingUpId)) {
                if (!view.hasDownloadPermission()) {
                    view.askForDownloadPermission(dbId);
                } else {
                    view.showDatabaseDownloadChoice(dbId);
                }
                return false;
            } else if (dbId.equals(noneId)) {
                // if the db ID is "none", delete the current DB and let the pref update
                try {
                    DBRegistry.instance().clear();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return true;
            }
        }

        return false;
    }

    @Override
    public void onDbDownloadChoiceResult(boolean result) {
        if (result) {
            PreferenceUtils.edit()
                    .putString(PreferenceKeys.DRUGDB_CURRENT_DB.key(), settingUpId)
                    .apply();
        }
    }

    @Override
    public void checkDatabaseUpdate(Context ctx) {
        new CheckDbUpdateTask(this).execute(ctx);
    }

    @Override
    public void onDownloadPermissionGranted(String dbId) {
        selectNewDb(dbId);
    }

    @Override
    public void start() {
        LogUtil.d(TAG, "start() called");
        Pair<String[], String[]> activeDbs = getActiveDbs();
        view.setDbList(activeDbs.second, activeDbs.first);
        if (view.getIntent().getBooleanExtra(
                CalendulaSettingsActivity.EXTRA_SHOW_DB_DIALOG,
                false
        )) {
            view.openDatabaseSelection();
            view.getIntent().removeExtra(CalendulaSettingsActivity.EXTRA_SHOW_DB_DIALOG);
        }
    }

    private Pair<String[], String[]> getActiveDbs() {
        // load values for db list
        List<String> registered = DBRegistry.instance().getRegistered();
        registered.add(0, noneId);
        String[] entryValues = (String[]) registered.toArray();

        List<String> temp = new ArrayList<>();
        for (int i = 1; i < entryValues.length; i++) {
            temp.add(DBRegistry.instance().db(entryValues[i]).displayName());
        }
        temp.add(0, noneDisplay);
        String[] entries = (String[]) temp.toArray();
        return new Pair(entries, entryValues);
    }

    class CheckDbUpdateTask extends
            AsyncTask<Context, Void, Boolean>{

        private DatabasePrefsPresenter presenter;

        public CheckDbUpdateTask(DatabasePrefsPresenter presenter){
            this.presenter = presenter;
        }

        @Override
        protected Boolean doInBackground(Context... contexts) {
            if (contexts.length == 1) {
                Context ctx = contexts[0];
                return new CheckDatabaseUpdatesJob().checkForUpdate(ctx);
            } else {
                throw new IllegalArgumentException("CheckDatabaseTag needs a Context!");
            }
        }

        @Override
        protected void onPostExecute(Boolean update) {
            if (!update) {
                presenter.notifyNoUpdate();
            }
        }
    }

    private void notifyNoUpdate() {
        view.showDatabaseUpdateNotAvailable();
    }
}
